package com.dz51.core.basedao.dao.impl;


import java.io.Serializable;
import java.sql.SQLException;
import java.util.Collection;
import java.util.List;
import java.util.Map;

import javax.annotation.Resource;
import javax.persistence.Entity;

import org.hibernate.Criteria;
import org.hibernate.HibernateException;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.criterion.DetachedCriteria;
import org.hibernate.criterion.Projections;
import org.hibernate.type.StandardBasicTypes;
import org.springframework.orm.hibernate3.HibernateCallback;

import com.dz51.core.basedao.base.impl.AbstractBaseDaoImpl;
import com.dz51.core.basedao.dao.IConditionSupport;
import com.dz51.core.basedao.query.IConditionBuilder;
import com.dz51.core.basedao.query.impl.DefaultQueryConditionBuilder;
import com.dz51.core.page.commond.BasePageCommond;
import com.dz51.core.utils.CheckAnnotationUtils;
/**
 * @Title: HibernateSupportDao
 * @Package com.dz51.core.basedao.dao
 * @Description: HibernateAbstract dao层支持
 * @author Zhaoqt  
 * @date 2014-5-4 上午5:56:10
 * @version V1.0
 */
public abstract class HibernateAbstractSupportDao<E>
		extends AbstractBaseDaoImpl<E> implements IConditionSupport{
    
	@Resource(name = "com.dz51.core.utils.CheckAnnotationUtils")
	protected CheckAnnotationUtils checkAnnotationUtils; 
    
	
    /**
     * @Title: addEntity
     * @Description: 实体储存 
     * @param entity
     * @throws Exception    
     * @return void
     */
    public void addEntity(E entity) throws Exception {
        if(entity != null) {
        	if(checkAnnotationUtils.checkAnnotation(entity, Entity.class)) {
        		this.save(entity);
        	} else {
        		this.log4jManager.errorCustomLog(
    	    			entity.getClass().getName(), "checkAnnotation", "该类上方没有定义Entity注解");
        	}
        } else {
        	this.log4jManager.errorCustomLog(
	    			getClass().getName(), "addEntity", "entity is null");
        }
    }
    
    /**
     * @Title: batchAddEntities
     * @Description: 实体批量储存
     * @param collection
     * @throws Exception    
     * @return void
     */
    public void batchAddEntities(Collection<E> collection) throws Exception {
        //  collection is not null
        if(collection != null && !collection.isEmpty()) {
	    	for(E entity : collection) {
	    		// 校验实体注解是否存在
	    	    if(checkAnnotationUtils.checkAnnotation(entity, Entity.class)) {
	    	    	this.save(entity);
	    	    } else {
	    	    	this.log4jManager.errorCustomLog(
	    	    			entity.getClass().getName(), "checkAnnotation", "该类上方没有定义Entity注解");
	    	    }
	    	}
        } else {
        	 this.log4jManager.errorCustomLog(getClass().getName(), "batchAddEntities", "collection is null");
        }
    }
    
    /**
     * @Title: updateEntityByPK
     * @Description: 主键更新实体 
     * @param entty
     * @throws Exception    
     * @return void
     */
    public void updateEntityByPK(E entity) throws Exception {
    	if(entity != null) {
    		// 校验实体注解是否存在
        	if(checkAnnotationUtils.checkAnnotation(entity, Entity.class)) {
        		// 批量调用更新清空上次session
    	    	this.clear();
        		this.update(entity);
        	} else {
        		this.log4jManager.errorCustomLog(
    	    			entity.getClass().getName(), "checkAnnotation", "该类上方没有定义Entity注解");
        	}
        } else {
        	this.log4jManager.errorCustomLog(
	    			getClass().getName(), "updateEntityByPK", "entity is null");
        }
    }
    
    /**
     * @Title: deleteEntityByPK
     * @Description: 主键删除实体 
     * @param entty
     * @throws Exception    
     * @return void
     */
    public void deleteEntityByPK(E entity) throws Exception {
    	if (entity != null) {
    		// 校验实体注解是否存在
        	if(checkAnnotationUtils.checkAnnotation(entity, Entity.class)) {
        		this.delete(entity);
        	} else {
        		this.log4jManager.errorCustomLog(
    	    			entity.getClass().getName(), "checkAnnotation", "该类上方没有定义Entity注解");
        	}
        } else {
            this.log4jManager.errorCustomLog(
    	    			getClass().getName(), "deleteEntityByPK", "entity is null");
        }
    }
    
    /**
     * @Title: batchDeleteEntities
     * @Description: 实体批量删除 
     * @param collection
     * @throws Exception    
     * @return void
     */
    public void batchDeleteEntities(Collection<E> collection) throws Exception {
    	 //  collection is not null
        if(collection != null && !collection.isEmpty()) {
	    	for(E entity : collection) {
	    		// 校验实体注解是否存在
	    	    if(checkAnnotationUtils.checkAnnotation(entity, Entity.class)) {
	    	    	this.delete(entity);
	    	    } else {
	    	    	this.log4jManager.errorCustomLog(
	    	    			entity.getClass().getName(), "checkAnnotation", "该类上方没有定义Entity注解");
	    	    }
	    	}
        } else {
        	 this.log4jManager.errorCustomLog(getClass().getName(), "batchDeleteEntities", "collection is null");
        }
    }
    
    /**
     * @Title: loadEntity
     * @Description:  session.load(..)
     * @param  className
     * @param  id
     * @throws Exception    
     * @return E
     */
    public E loadEntity(Class<E> className, Serializable id) throws Exception {
    	return this.load(className, id);
    }
    
    /**
     * @Title: getEntity
     * @Description: session.get(..) 
     * @param className
     * @param id
     * @return
     * @throws Exception    
     * @return E
     * @throws
     */
    public E getEntity(Class<E> className, Serializable id) throws Exception {
    	return this.get(className, id);
    }
    
    
    /**
     * @Title: loadEntity
     * @Description:  session.load(..)
     * @param  id
     * @throws Exception    
     * @return E
     */
    @Override
	public Object loadEntity(Serializable id) throws Exception {
		return this.load(entityClass, id);
	}

    /**
     * @Title: getEntity
     * @Description: session.get(..) 
     * @param id
     * @return
     * @throws Exception    
     * @return E
     * @throws
     */
	@Override
	public Object getEntity(Serializable id) throws Exception {
		return this.get(entityClass, id);
	}

	/**
     *  条件查询db数据.
     * </p>
     * -----------包含sql、hql两种查询语言------------.
     * </p>
     * -----------paramMap key查询条件匹配符  value查询条件匹配值.
     * </p>
     * @Title: executeFind
     * @param queryStringType
     * @param sqlOrHql
     * @param paramMap
     * @param start
     * @param end
     * @return List<?>
     * @throws Exception
     */
    public List<?> executeFind(final QueryStringType queryStringType,
    		final String sqlOrHql, final Map<String, Object> paramMap, final int firstResult, final int maxResult)
    		throws Exception {
    	
    	this.execute(new HibernateCallback<Object>(){
    		
			public Object doInHibernate(Session session)
					throws HibernateException, SQLException {
				Query query = null;
				
    			if (QueryStringType.HQL.equals(queryStringType)) {
    				query = session.createQuery(sqlOrHql);
    			} else if(QueryStringType.SQL.equals(queryStringType)) {
    				  query = session.createSQLQuery(sqlOrHql);
    			} else {
    				query = session.createQuery(sqlOrHql);
    			}
    			if ((paramMap != null) && (paramMap.size() > 0)) {
    		          query.setProperties(paramMap);
    		    }
    			
    			if (firstResult > 0) {
    				query.setFirstResult(firstResult);
		        }
		        if (maxResult > 0) {
		        	query.setMaxResults(maxResult);
		        }
		        return query.list();
			}
		});
    	this.log4jManager.errorCustomLog(getClass().getName(), "executeFind", "find Invalid");
    	return null;
    }
    
    /**
	 * count 查询
	 *  </p>
	 * -----------包含sql、hql两种查询语言------------.
	 * </p>
	 * -----------paramMap key查询条件匹配符  value查询条件匹配
	 * @Title: count
	 * @param queryStringType
	 * @param sqlOrHql
	 * @param paramMap
	 * @return
	 * @throws ExceptionLong
	 */
	public Long count(final QueryStringType queryStringType, final String sqlOrHql,
			final Map<String, Object> paramMap) throws Exception {
		this.execute(new HibernateCallback<Long>() {
		      public Long doInHibernate(Session session)
		        throws HibernateException, SQLException {
		    	
		    	 int startIndex = -1;
		    	String countHQL = ""; 
		       
		        if ((startIndex = sqlOrHql.indexOf(" ORDER BY ")) != -1) {
		        	countHQL = countHQL.substring(0, startIndex);
		        }
		        Query query = null;
		        if (QueryStringType.SQL.equals(queryStringType)) {
		        	query = session.createSQLQuery(
		        		  "SELECT COUNT(*) as count " + countHQL).addScalar("count", StandardBasicTypes.LONG);
		        } else {
		        	query = session.createQuery("SELECT COUNT(*) " + countHQL);
		        }
		        if (paramMap != null && paramMap.size() > 0) {
		        	query.setProperties(paramMap);
		        }
		        return (Long)query.list().iterator().next();
		      }
		    });
		this.log4jManager.errorCustomLog(getClass().getName(), "count", "find Invalid");
		return null;
	}

	/**
	 * {@link com.dz51.core.basedao.query.IConditionBuilder}
	 * @Title: find
	 * @param conditionBuilder
	 * @return
	 * @throws Exception
	 */
	@Override
	public BasePageCommond find(IConditionBuilder conditionBuilder) throws Exception {
		BasePageCommond basePageCommond = new BasePageCommond();
		DefaultQueryConditionBuilder 
					defaultQueryConditionBuilder = (DefaultQueryConditionBuilder) conditionBuilder;
		boolean isCriteria = defaultQueryConditionBuilder.isCriteria();
		//-------------------- 启用 Criteria查询  start --------------------------------------//
		 if(isCriteria) {
			 DetachedCriteria detachedCriteria = DetachedCriteria.forClass(entityClass);
			 Criteria criteria = detachedCriteria.getExecutableCriteria(getSession());
			 defaultQueryConditionBuilder.setCriteria(criteria);
			 //关键词  属性查询 方法内部验证。关键字为空则不执行
			 defaultQueryConditionBuilder.addCriteriaKeyword();
			 // 属性集查询    方法内部验证。map为空则不执行
			 defaultQueryConditionBuilder.addCriteriaMap();
			 // 查询数据最大数量
			 Object obj = criteria.setProjection(Projections.rowCount()).uniqueResult();
			 Integer totalCount = new Integer("0");
			 if (obj instanceof Long) {
				totalCount = ((Long) obj).intValue();
			 } else if (obj instanceof Integer) {
				totalCount = (Integer) obj;
			 }
			 criteria.setProjection(null);
			 //分页计算查询
			 defaultQueryConditionBuilder.addCriteriaPager();
			 // 排序
			 defaultQueryConditionBuilder.addCriteriaOrder();
			 
			 basePageCommond.setPageCount(totalCount);
			 basePageCommond.setResultCollection(criteria.list());
		 }
		//-------------------- 启用 Criteria查询  end --------------------------------------//
		 
		return basePageCommond;
	}
    
}
